/*
 *  ckr_spec_not_equal_comparisons.cpp
 *  ckrSpec
 *
 *  Created by C. Keith Ray on 2006.11.05.
 *  Copyright 2006 __MyCompanyName__. All rights reserved.
 *
 */

#import "ckr_spec_cpp_specs.h"
#import "ckr_spec_cpp.h"

#include <iostream>
#include <sstream>
#include <vector>
#include <deque>

#include <assert.h>

using namespace std;
using namespace ckr;

//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

static void integral_values_not_equal_in_should_not_equal_should_report_nothing();
static void integral_values_equal_in_should_not_equal_should_report_failure_operation();

static void c_string_not_equal_in_should_not_equal_reports_nothing();
static void c_strings_equal_in_should_not_equal_reports_failure();
static void c_string_null_in_should_not_equal_reports_failure();

//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

void run_not_equal_comparison_specs()
{
	integral_values_not_equal_in_should_not_equal_should_report_nothing();
	integral_values_equal_in_should_not_equal_should_report_failure_operation();

	c_string_not_equal_in_should_not_equal_reports_nothing();
	c_strings_equal_in_should_not_equal_reports_failure();
	c_string_null_in_should_not_equal_reports_failure();
}

//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// We know that all of the integral values SHOULD_NOT_EQUAL / should_not_equal_impl is the 
// same macro and same template function, so we don't need to spec ALL of the different
// types (int, short, long, char, unsigned int, etc.)

DECLARE_SPEC(Integral_values_not_equal_in_should_not_equal_context);

void Integral_values_not_equal_in_should_not_equal_context::spec()
{
	int int98 = 98;
	VALUE( int98 ).SHOULD_NOT_EQUAL( 45 ); // no msg expected
}

static void integral_values_not_equal_in_should_not_equal_should_report_nothing()
{
	Integral_values_not_equal_in_should_not_equal_context aContext;

	RecordingFailuresSpecListener listener;
	aContext.run_spec( & listener );
	std::string actual = listener.logStr();

	std::string expected; // empty string

	assert( expected == actual );
}

//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

DECLARE_SPEC(Integral_values_equal_in_should_not_equal_context);

void Integral_values_equal_in_should_not_equal_context::spec()
{
	int int98 = 98;
	int int98Also = 98;
	VALUE( int98 ).SHOULD_NOT_EQUAL( int98Also ); // fail msg expected
}

static void integral_values_equal_in_should_not_equal_should_report_failure_operation()
{
	Integral_values_equal_in_should_not_equal_context aContext;

	RecordingFailuresSpecListener listener;
	aContext.run_spec( & listener );
	std::string actual = listener.logStr();

	std::string expected( "int98 (98) should not equal int98Also (98) FAILED in Integral_values_equal_in_should_not_equal_context; line " );

	std::string::size_type foundPos = actual.find( expected, 0 );

	assert( foundPos != std::string::npos );
}

// Now we see the need for line numbers, filename, and to display the actual expressions
// in the failure messages.  Time for some macros.

// Not just macros... a big change. Good thing we have these specs. But I am working a rather long time without
// doing the spec-code-refactor cycle. Now I have a bunch of specs to fix because I changed behavior without
// driving that change via specs. 

// long time later... done!

//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// We're getting too much duplication in AssertableValue<T>::should_be_... methods.  Time to refactor.
// created ckr_spec_AssertableValue.h and ckr_spec_AssertableValue.i. 
// created new private method report_failure_operation.
// Created ckr_spec_AssertableValueCString.h and .cpp.  Discovered that there is no
// spec for CString NOT_EQUAL, particularly for null values.

DECLARE_SPEC(CString_values_not_equal_in_should_not_equal_context);

void CString_values_not_equal_in_should_not_equal_context::spec()
{
	const char* number99 = "99";
	const char* smart = "Smart";

	CSTRING_VALUE( number99 ).SHOULD_NOT_EQUAL( smart );   // no msg expected
}

static void c_string_not_equal_in_should_not_equal_reports_nothing()
{
	CString_values_not_equal_in_should_not_equal_context aContext;

	RecordingFailuresSpecListener listener;
	aContext.run_spec( & listener );
	std::string actual = listener.logStr();
	
	std::string expected;//empty
	assert( expected == actual );
}

//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

DECLARE_SPEC(CString_values_equal_in_not_equal_context);

void CString_values_equal_in_not_equal_context::spec()
{
	const char* number99 = "99";
	const char* other99 = "99";
	const char* agentNull = NULL;

	CSTRING_VALUE( number99 ).SHOULD_NOT_EQUAL( other99 );		// fail msg expected because the values are equal.
	CSTRING_VALUE( agentNull ).SHOULD_NOT_EQUAL( agentNull );	// fail msg expected because the values are equal.
}

static void c_strings_equal_in_should_not_equal_reports_failure()
{
	CString_values_equal_in_not_equal_context aContext;

	RecordingFailuresSpecListener listener;
	aContext.run_spec( & listener );
	std::string actual = listener.logStr();

	{
		std::string expected2( "number99 (99) should not equal other99 (99) FAILED in CString_values_equal_in_not_equal_context; line " );
		std::string::size_type foundPos2 = actual.find( expected2, 0 );
		assert( foundPos2 != std::string::npos );
	}
	{
		std::string expected4( "agentNull ((NULL POINTER)) should not equal agentNull ((NULL POINTER)) FAILED in CString_values_equal_in_not_equal_context; line " );
		std::string::size_type foundPos4 = actual.find( expected4, 0 );
		assert( foundPos4 != std::string::npos );
	}
}

//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

DECLARE_SPEC(CString_nulls_in_not_equal_context);

void CString_nulls_in_not_equal_context::spec()
{
	const char* number99 = "99";
	const char* smart = "Smart";
	const char* agentNull = NULL;

	CSTRING_VALUE( agentNull ).SHOULD_NOT_EQUAL( smart );		// fail msg expected because we don't want NULLPTRS to ever compare to a string "successfully"
	CSTRING_VALUE( number99 ).SHOULD_NOT_EQUAL( agentNull );	// fail msg expected because we don't want NULLPTRS to ever compare to a string "successfully"
}

void c_string_null_in_should_not_equal_reports_failure()
{
	CString_nulls_in_not_equal_context aContext;

	RecordingFailuresSpecListener listener;
	aContext.run_spec( & listener );
	std::string actual = listener.logStr();

	{
		std::string expected2( "agentNull ((NULL POINTER)) should not equal smart (Smart) FAILED in CString_nulls_in_not_equal_context; line " );
		std::string::size_type foundPos2 = actual.find( expected2, 0 );
		assert( foundPos2 != std::string::npos );
	}
	{
		std::string expected3( "number99 (99) should not equal agentNull ((NULL POINTER)) FAILED in CString_nulls_in_not_equal_context; line " );
		std::string::size_type foundPos3 = actual.find( expected3, 0 );
		assert( foundPos3 != std::string::npos );
	}
}

//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
